package com.mini.mybatis.mybatisministep10.datasource.unpooled;

import com.mini.mybatis.mybatisministep10.datasource.DataSourceFactory;
import com.mini.mybatis.mybatisministep10.reflection.MetaObject;
import com.mini.mybatis.mybatisministep10.reflection.SystemMetaObject;

import javax.sql.DataSource;
import java.util.Properties;

public class UnPooledDataSourceFactory implements DataSourceFactory {

    protected DataSource dataSource;

    public UnPooledDataSourceFactory(){
        this.dataSource = new UnPooledDataSource();
    }

    @Override
    public void setProperties(Properties properties) {
        // 获取dataSource元对象 此时的Class<?> type 为PooledDataSource(因为是根据配置文件配置的，所以这里就有模板模式那感觉了，不需要实例化具体的子类了)
        MetaObject metaObject = SystemMetaObject.forObject(dataSource);
        // 循环props, key 为 driver..url..username..password
        for (Object key : properties.keySet()) {
            String propName = (String) key;
            // 查询元对象中是否有当前属性的set方法，如setPassword
            if (metaObject.hasSetter(propName)){
                // 获取password的value
                String value = properties.getProperty(propName);
                // 根据元对象中set方法的入参类型，将value转化为对应的类型，此处相当于一个适配
                Object convertValue = convertValue(metaObject, propName, value);
                // 设置对应的属性，如果是集合类（那么此处没那么简单）
                metaObject.setValue(propName,convertValue);
            }
        }
    }

    @Override
    public DataSource getDataSource() {
        return dataSource;
    }

    /**
     * 根据setter的类型,将配置文件中的值强转成相应的类型
     */
    private Object convertValue(MetaObject metaObject, String propertyName, String value) {
        Object convertedValue = value;
        Class<?> targetType = metaObject.getSetterType(propertyName);
        if (targetType == Integer.class || targetType == int.class) {
            convertedValue = Integer.valueOf(value);
        } else if (targetType == Long.class || targetType == long.class) {
            convertedValue = Long.valueOf(value);
        } else if (targetType == Boolean.class || targetType == boolean.class) {
            convertedValue = Boolean.valueOf(value);
        }
        return convertedValue;
    }
}
